package services

import (
	"fmt"
	"gitee.com/captials-team/ubdframe/src/domain/dto"
	"gitee.com/captials-team/ubdframe/src/domain/dto/paginate"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/domain/models"
	"gitee.com/captials-team/ubdframe/src/infrastructure/caches"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"go.uber.org/dig"
)

type BlockService struct {
	l           v1log.ILog
	dao         interfaces.ItfBlockContentDao
	cacheById   *caches.CacheFacade[int64, *models.BlockContent]
	cacheByCode *caches.CacheFacade[string, *models.BlockContent]
}

func NewBlockService(di *dig.Container, l v1log.ILog, blockDao interfaces.ItfBlockContentDao, cache caches.ItfCache) *BlockService {
	svc := &BlockService{
		l:           l,
		dao:         blockDao,
		cacheById:   caches.NewCacheFacade[int64, *models.BlockContent](cache),
		cacheByCode: caches.NewCacheFacade[string, *models.BlockContent](cache),
	}

	svc.cacheById.WithValueFunc(svc.blockCache).WithKeyPrefix("block_")
	svc.cacheByCode.WithValueFunc(svc.blockCacheByCode).WithKeyPrefix("block_code_")

	return svc
}

func (s *BlockService) blockCache(k int64) *models.BlockContent {
	find, err := s.dao.Query(k)
	if err != nil {
		return nil
	}
	return find
}

func (s *BlockService) blockCacheByCode(k string) *models.BlockContent {
	find, err := s.dao.QueryByCode(k)
	if err != nil {
		return nil
	}
	return find
}

func (s *BlockService) Query(id int64, code string) (*models.BlockContent, error) {
	if id > 0 {
		return s.dao.Query(id)
	}
	if len(code) > 0 {
		return s.dao.QueryByCode(code)
	}
	return nil, fmt.Errorf("invalid")
}

func (s *BlockService) QueryByCode(code string) (*models.BlockContent, error) {
	return s.dao.QueryByCode(code)
}

func (s *BlockService) Save(id int64, b *models.BlockContent) (int64, error) {
	if id > 0 {
		return s.dao.Update(id, b)
	}
	return s.dao.Add(b)
}

func (s *BlockService) Search(search *dto.SearchBlockContentParams, pa *paginate.Pager) ([]*models.BlockContent, *paginate.Pager, error) {
	return s.dao.Search(search, pa)
}

func (s *BlockService) GetFromCache(code string) (*models.BlockContent, error) {
	return s.cacheByCode.GetOrLoad(code)
}

func (s *BlockService) Delete(id int64) (int64, error) {
	b, err := s.dao.Query(id)
	if err != nil {
		return 0, err
	}
	if b == nil {
		return 0, nil
	}
	defer s.cacheById.Delete(id)
	defer s.cacheByCode.Delete(b.Code)

	return s.dao.Delete(id)
}

func (s *BlockService) CacheKeyForCode(key string) string {
	return "block_code_" + key
}

func (s *BlockService) CacheKeyForId(key int64) string {
	return fmt.Sprintf("block_id_%d", key)
}
